package com.kai.mpc_plugin

import android.os.AsyncTask
import android.util.Log

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import org.json.JSONObject

/** MpcPlugin */
class MpcPlugin : FlutterPlugin, MethodCallHandler {
    /// The MethodChannel that will the communication between Flutter and native Android
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private lateinit var channel: MethodChannel
    override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "mpc_plugin")
        channel.setMethodCallHandler(this)
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        when (call.method) {
            "solSignTx" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        //String tx, String mpcA, String mpcB, String salt
                        val tx = jsonObject.optString("tx")
                        val mpcA = jsonObject.optString("mpcA")
                        val mpcB = jsonObject.optString("mpcB")
                        val salt = jsonObject.optString("salt")
                        val result0 = MPCNative.mpcInstance.solSignTx(tx, mpcA, mpcB, salt)
                        data.put("result", result0)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }


            "upgradeMPC" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag1 = jsonObject.optString("frag1")
                        val frag2 = jsonObject.optString("frag2")
                        val salt = jsonObject.optString("salt")
                        val mpc = MPCNative.mpcInstance.upgradeMPC(frag1, frag2, salt);
                        if (mpc.isNullOrBlank()) {
                            result.success(data.toString())
                            return@execute
                        }
                        val mpcArray = mpc.split(";")
                        if (mpcArray.size < 3) {
                            result.success(data.toString())
                            return@execute
                        }
                        data.put("mpcPieceA", mpcArray[0])
                        data.put("mpcPieceB", mpcArray[1])
                        data.put("mpcPieceC", mpcArray[2])
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "getVersionFromFrag" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    var data = 0;
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag1 = jsonObject.optString("frag")
                        data = MPCNative.mpcInstance.getVersionFromFrag(frag1);
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "getAddress" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    var data = JSONObject();
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag1 = jsonObject.optString("frag")
                        val chainId = jsonObject.optString("chainId")
                        var res = MPCNative.mpcInstance.getAddress(frag1,chainId);
                        // val mpcArray = res.split(" ");
                        System.out.println("Log message $res");
                        data.put("address", res.toString())
                        // data.put("address", mpcArray[1])
                        data.put("chainId", chainId)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "getPlatformVersion" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        data.put("version", "Android ${android.os.Build.VERSION.RELEASE}")
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "getLibVersion" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val version = MPCNative.mpcInstance.version
                        data.put("version", version)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }

                }
            }

            "forgingMPC" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        Log.e("test", "data0:${arguments}")
                        val jsonObject = JSONObject(arguments)
                        val salt = jsonObject.optString("salt")
                        val path = jsonObject.optString("path")
                        val mpc = MPCNative.mpcInstance.forgingMPCJava(salt, path)
                        if (mpc.isNullOrBlank()) {
                            result.success(data.toString())
                            return@execute
                        }
                        val mpcArray = mpc.split(";")
                        if (mpcArray.size < 3) {
                            result.success(data.toString())
                            return@execute
                        }
                        data.put("mpcPieceA", mpcArray[0])
                        data.put("mpcPieceB", mpcArray[1])
                        data.put("mpcPieceC", mpcArray[2])
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "useMnemonicForgingMPC" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val mne = jsonObject.optString("mne")
                        val salt = jsonObject.optString("salt")
                        val path = jsonObject.optString("path")
                        val mpc = MPCNative.mpcInstance.useMnemonicForgingMPCJava(mne, salt, path)
                        if (mpc.isNullOrBlank()) {
                            result.success(data.toString())
                            return@execute
                        }
                        val mpcArray = mpc.split(";")
                        if (mpcArray.size < 3) {
                            result.success(data.toString())
                            return@execute
                        }
                        data.put("mpcPieceA", mpcArray[0])
                        data.put("mpcPieceB", mpcArray[1])
                        data.put("mpcPieceC", mpcArray[2])
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }


            "freeForgingMPC" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val ptr = jsonObject.optString("ptr")
                        MPCNative.mpcInstance.freeForgingMPC(ptr)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }


            "verifyMPCFragment" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag = jsonObject.optString("frag")
                        val result0 = MPCNative.mpcInstance.verifyMPCFragment(frag)
                        data.put("result", result0)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }

                }
            }

            "recoverMPCFragment" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag1 = jsonObject.optString("frag1")
                        val frag2 = jsonObject.optString("frag2")
                        val result0 = MPCNative.mpcInstance.recoverMPCFragment(frag1, frag2)
                        data.put("result", result0)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }
            // 该 接口 弃用
            "mpcFragmentGetPublicKey" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag = jsonObject.optString("frag")
                        val result0 = MPCNative.mpcInstance.mpcFragmentGetPublicKey(frag)
                        data.put("result", result0)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "mpcEscape" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        val frag1 = jsonObject.optString("frag1")
                        val frag2 = jsonObject.optString("frag2")
                        val salt = jsonObject.optString("salt")
                        Log.e("mpcEscape", "mpcEscape===:${salt}");
                        val result0 = MPCNative.mpcInstance.mpcEscapeJava(frag1, frag2, salt)
                        if (result0.isNullOrBlank()) {
                            result.success(data.toString())
                            return@execute
                        }
                        val escapeArray = result0.split(";")
                        if (escapeArray.size < 2) {
                            result.success(data.toString())
                            return@execute
                        }
                        val bytes0 = HexUtils.hexString2Bytes(escapeArray[0])
                        val bytes1 = HexUtils.hexString2Bytes(escapeArray[1])
                        data.put("mnemonic", String(bytes0))
                        data.put("path", String(bytes1))
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            "signTx" -> {
                AsyncTask.THREAD_POOL_EXECUTOR.execute {
                    val data = JSONObject()
                    try {
                        val arguments = call.arguments.toString()
                        val jsonObject = JSONObject(arguments)
                        //String tx, String mpcA, String mpcB, String salt
                        val tx = jsonObject.optString("tx")
                        val mpcA = jsonObject.optString("mpcA")
                        val mpcB = jsonObject.optString("mpcB")
                        val salt = jsonObject.optString("salt")
                        val result0 = MPCNative.mpcInstance.signTx(tx, mpcA, mpcB, salt)
                        data.put("result", result0)
                        result.success(data.toString())
                    } catch (ignored: Throwable) {
                        ignored.printStackTrace()
                        result.success(data.toString())
                    }
                }
            }

            else -> {
                result.notImplemented()
            }
        }
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
    }
}
